/*
 * @Description:
 * @Autor: HuiSir<273250950@qq.com>
 * @Date: 2021-05-20 15:16:16
 * @LastEditTime: 2021-05-20 16:40:36
 */

/**
 * 装饰器特性目前为实验性特性，你必须在命令行或tsconfig.json里启用experimentalDecorators编译器选项
 */

/**
 * 装饰器是一种特殊类型的声明，它能够被附加到类声明，类的方法， 类的访问符，类的属性或类的参数上。
 * 装饰器使用 @expression这种形式，expression求值后必须为一个函数，它会在运行时被调用，被装饰的声明信息做为参数传入。
 * 类装饰器 或  类的方法装饰器 ，在实例化（new）之后就会执行一次
 */

(function () {
	
	const Method = (m: 'GET' | 'POST' | 'PUT' | 'DELETE') => {
		return (target: any, fnName: string, desc: any) => {
			// 修改原方法
			let curr = desc.value
			desc.value = (data: any, method: string) => {
				if (method.toUpperCase() !== m) {
					return { status: 405, msg: 'Method Not Allowed' }
				}
				return curr.call(target, data)
			}
		}
	}


    function test1(a:any) {
        console.log("test1", a)
        return (target:any, key:any, desc:any) => {
            console.log("target-test1", a)
			
			// fn只是class中方法的合集，不帶屬性
			
			// fn.setMethod(key,a)
			
			let curr = desc.value
			desc.value = (arg1: string, arg2: string) => {
				console.log("call-test1",a)
				return curr.call(target, 23131,23424)
			}
        }
    }

    function test2(b:any) {
		console.log("test2",b)
        return (target:any, key:any, desc:any) => {
			console.log("target-test2",b)
            let curr = desc.value
            desc.value = (arg1: string, arg2: string) => {
				console.log("call-test2",b)
            	return curr.call(target, 0,0)
            }
        }
    }
	
	function Test0(aaa) {
	    return function (target, key) {
			console.log('target[key]',key,typeof target[key])
			// if(target[key]){
			// 	throw new Error('This decorator is a property decorator and can only be used for properties.')
			// }
			
	        // target[key] = aaa
	        if (target.aaa) {
	            target.aaa.push(key);
	        }
	        else {
	            target.aaa = [key];
	        }
	    };
	}

    class A {
		@Test0("456")
		methods:Map<string, string>
		
		@Test0("312")
		aaa:string = "2131313"
		
		constructor(){
			this.methods = new Map()
		}
		@Test0("45132")
		setMethod(key:string,method:string){
			// this.methods.set(key,method) // 報錯
			console.log('this.methods',this.methods) // undifined
		}
		
		@Method('GET')
		test(data:any,method:string){
			return data
		}
		
        @test1('aaa')
        @test2(2)
        test888(arg1:string,arg2:string) {
            console.log("test888",arg1,arg2)
        }
    }

    // new A().test888('arg1','arg2')  // 打印：0,0
    A.prototype.test888('arg1','arg2')  // 打印：0,0

	
	// var aaa = new A().test(123,"get")
	// var bbb = new A().test(123,"post")
	// console.log("===aaa",aaa)
	// console.log("===bbb",bbb)
	// ===aaa 123
	// ===bbb { status: 405, msg: 'Method Not Allowed' }

})()